
package ib_cluster.networks;

import ib_model.src.*;
import ib_cluster.network_module.channels.*;
import ib_cluster.network_module.control.*;
import ib_cluster.network_module.computation.*;

network tree
{
    parameters:
        // // it is suggested that the numMachine should be a multiple of the number of lowest level switch
        int numMachine = default(4);
        int numL1switch = default(2);
        int numGpusperMachine = default(8);
        int switch_delay = default(0);

    submodules:

        machine[numMachine]: Machine 
        {
            parameters:
            	 numGpus = numGpusperMachine;
                my_index = index;
                @display("i=device/server2;p=80,109");
        }

        taskgenerator: TaskGenerator
        {
            parameters:
                maxnumGpus = numGpusperMachine * numMachine;
        }

        centralcontroller: CentralController 
        {
            parameters:
                numMachine = numMachine;
                numSwitch = numL1switch + 1;
                numGpusperMachine = numGpusperMachine;
            gates:
                machine_port[numMachine];
                switch_port[numL1switch + 1];
        }

        topo_manager : TopoManager 
        {
        }	

        sw[numL1switch]: Switch 
        {
            parameters:
                numSwitchPorts = int(numMachine/numL1switch)*numGpusperMachine + 1;
                @display("p=182,58");
            gates:
                port[int(numMachine/numL1switch)*numGpusperMachine + 1];
        }

        core: Switch 
        {
            parameters:
                numSwitchPorts = numL1switch;
                @display("p=182,58");
            gates:
                port[numL1switch];
        }

        virtual_switch: IB_Virtual_Data_Switch 
        {
            parameters:
                numSwitchPorts = numMachine*numGpusperMachine;
            gates:
                port[numMachine*numGpusperMachine];
        }

    connections allowunconnected:

        // Connect the task generater and centralcontroller
        taskgenerator.central_controller_port --> centralcontroller.task_generater_port;

        // Connect every machines to its respective L1 switch, central controller and virtual data switch
        for j = 0..numMachine-1
        {
            machine[j].controller_port <--> ControlPlane <--> centralcontroller.machine_port[j];
        }

	    for i=0..numMachine-1, for j=0..numGpusperMachine-1 
	    {
	    virtual_switch.port[i*numGpusperMachine+j] <--> ControlPlane <--> machine[i].virtual_data_switch_port[j];
        machine[i].out_port[j] <--> IB4XQDRWire <--> sw[int(i/int(numMachine/numL1switch))].port[(j+i*numGpusperMachine) % (int(numMachine/numL1switch)*numGpusperMachine)];
        }	

        // Connect the L1 switches to core switch as well as central controller
        for i = 0..numL1switch-1
        {
            sw[i].port[int(numMachine/numL1switch)*numGpusperMachine] <--> IB4XQDRWire <--> core.port[i];
            sw[i].central_controller_port <--> ControlPlane <--> centralcontroller.switch_port[i];
        }

        // Connect the core switch to central controller
        centralcontroller.switch_port[numL1switch] <--> ControlPlane <--> core.central_controller_port;
}